package com.wutuo.aggragation.rollcall.service;

import cn.apestar.Chat;
import cn.apestar.ChatInstance;
import cn.apestar.agg.user.info.service.UserService;
import cn.apestar.cloud.api.enums.MessageWTType;
import cn.apestar.cloud.api.enums.PeoPleType;
import cn.apestar.core.framework.exception.BusinessException;
import cn.apestar.core.http.AppType;
import cn.apestar.core.utils.DateEnum;
import cn.apestar.core.utils.DateUtils;
import cn.apestar.user.provider.info.domain.User;
import cn.apestar.user.provider.institution.response.InstitutionResponse;
import cn.apestar.user.provider.institution.service.InstitutionService;
import cn.apestar.util.CommonUtil;
import com.wutuo.aggragation.rollcall.dao.TaskDetailMapper;
import com.wutuo.aggragation.rollcall.dao.TaskMapper;
import com.wutuo.aggragation.rollcall.domain.Task;
import com.wutuo.aggragation.rollcall.domain.TaskDetail;
import com.wutuo.aggragation.rollcall.request.AddRollCallTaskRequest;
import com.wutuo.aggragation.rollcall.request.AddSignRequest;
import com.wutuo.aggragation.rollcall.request.ListRollCallTaskRequest;
import com.wutuo.aggragation.rollcall.request.ListSignRequest;
import com.wutuo.aggragation.rollcall.response.AddRollCallTaskResponse;
import com.wutuo.aggragation.rollcall.response.ListSignDetailResponse;
import com.wutuo.aggragation.rollcall.response.ListSignResponse;
import com.wutuo.aggragation.rollcall.util.RollCallDataConvert;
import com.wutuo.aggragation.rollcall.vo.CallVo;
import com.wutuo.aggragation.rollcall.vo.ListSignItem;
import com.wutuo.aggragation.rollcall.vo.RollCallListVo;
import com.wutuo.aggragation.rollcall.vo.SignDetailItem;
import com.wutuo.child.api.response.ParentChildResponse;
import com.wutuo.child.provider.enums.RollCallState;
import com.wutuo.child.provider.service.ChildService;
import com.wutuo.enums.TaskType;
import com.wutuo.roster.api.request.SearchRosterRequest;
import com.wutuo.roster.api.response.RosterResponse;
import com.wutuo.roster.provider.constant.TgStateEnum;
import com.wutuo.roster.provider.domain.Roster;
import com.wutuo.roster.provider.service.ParentsService;
import com.wutuo.roster.provider.service.RosterService;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.ListUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;

import static cn.apestar.cloud.api.enums.MessageType.TXT;

@Service
public class RollCallTaskService {

    /**
     * 日志记录器
     */
    private Logger logger = LoggerFactory.getLogger(RollCallTaskService.class);

    @Autowired
    private TaskMapper taskMapper;

    @Autowired
    private TaskDetailMapper taskDetailMapper;

    @Autowired
    private RosterService rosterService;

    @Autowired
    private UserService userService;

    @Autowired
    private ParentsService parentsService;

    @Autowired
    private InstitutionService institutuionService;

    @Autowired
    private ChildService childService;

    public Task getTaskById(Long taskId) {
        if (taskId == null) {
            return null;
        }
        return taskMapper.selectByPrimaryKey(taskId);
    }

    public AddRollCallTaskResponse add(AddRollCallTaskRequest request) {

        Long userId = request.getTeacherId();

        Task old = taskMapper.selectByIntitutionAndName(request.getInsitutionId(), request.getTaskName(), new Date());
        if (old != null) {
            return RollCallDataConvert.buildAddRollCallTaskResponse(old, 0, 0);
        }

        Date now = new Date();
        Task task = new Task();
        task.setCreateBy(userId);
        task.setDelFlag(String.valueOf(1));
        task.setCreateDate(now);
        task.setTaskName(request.getTaskName());
        task.setTaskTime(request.getTaskTime());
        task.setTaskType(TaskType.getByText(task.getTaskName()).getValue());
        task.setUpdateBy(userId);
        task.setUpdateDate(now);
        task.setInstitutionId(request.getInsitutionId());

        taskMapper.insert(task);

        // TODO : 取数逻辑完善
        return RollCallDataConvert.buildAddRollCallTaskResponse(task, 0, 0);
    }

    public List<RollCallListVo> list(ListRollCallTaskRequest request, Long institutionId) {

        int index = (request.getIndex() - 1) * request.getSize();

        List<Task> tasks = taskMapper.selectByInstitutionId(institutionId, index, request.getSize());
        if (CollectionUtils.isEmpty(tasks)) {
            return Collections.emptyList();
        }

        List<RollCallListVo> response = new ArrayList<>();
        SearchRosterRequest s = new SearchRosterRequest();
        s.setTgZt(TgStateEnum.TG_ZT.getValue());
        s.setCmInstitutionId(institutionId);
        int total = rosterService.countInstitutionChildren(s);
        for (Task task : tasks) {
            RollCallListVo item = new RollCallListVo();
            item.setEditable(this.isTaskEditable(task.getTaskTime()));
            item.setTotalStudentNum(total < 0 ? 0 : total);
            int inTimeCount = taskDetailMapper.countSignedChildren(RollCallState.SIGNED.getValue(), task.getId(), null);
            item.setInTimeStudentNum(inTimeCount < 0 ? 0 : inTimeCount); // TODO
            int lateCount = taskDetailMapper.countSignedChildren(RollCallState.LATE.getValue(), task.getId(), null);
            item.setLateNum(lateCount < 0 ? 0 : lateCount);
            item.setTaskId(task.getId());
            item.setTaskName(task.getTaskName());
            item.setTaskTime(task.getTaskTime());
            response.add(item);
        }
        return response;
    }

    private boolean isTaskEditable(Date taskTime) {

        if (taskTime == null) {
            return false;
        }

        Date now = DateUtils
            .parseDate(DateUtils.formatDate(new Date(), DateEnum.YYYYMMDD_BYSEP), DateEnum.YYYYMMDD_BYSEP);
        Date taskTimeDate = DateUtils
            .parseDate(DateUtils.formatDate(taskTime, DateEnum.YYYYMMDD_BYSEP), DateEnum.YYYYMMDD_BYSEP);
        return taskTimeDate.compareTo(now) >= 0;

    }

    // TODO : unfinished
    public List<ListSignItem> listSign(Long taskId, Long institutionId, ListSignRequest request) {

        // Query children by institution 、 year & tags
        SearchRosterRequest searchChildRequest = new SearchRosterRequest();
        // searchChildRequest.setParentId(userId);
        // searchChildRequest.setTeacherId(teacherId);
        searchChildRequest.setCmId(institutionId.toString());
        searchChildRequest.setYear(request.getYear());
        searchChildRequest.setTgZt(TgStateEnum.TG_ZT.getValue());
        if (request.getTagId() != null) {
            searchChildRequest.setTagId(String.valueOf(request.getTagId()));
        }
        List<RosterResponse> children = rosterService.lisForPage(searchChildRequest);
        if (CollectionUtils.isEmpty(children)) {
            return Collections.emptyList();
        }

        List<Long> childIds = new ArrayList<>();
        for (RosterResponse childResponse : children) {
            childIds.add(childResponse.getId());
        }

        // Build roster map by rosterId
        Map<String, RosterResponse> rosterMap = CommonUtil.listToObject(children, "id");

        // Get signed list
        List<TaskDetail> signList = taskDetailMapper.selectByChildIds(childIds, request.getTaskId(), null);

        // Get teachers ids
        Set<Long> teacherIds = RollCallDataConvert.getTeacherId(signList);
        // Get info of teachers
        Map<Long, User> userInfoMap = userService.multiGetUserByIds(teacherIds);

        return RollCallDataConvert.convertTaskDetailsToSignItem(signList, rosterMap, userInfoMap);
    }

    public List<ListSignItem> listUnsign(Long taskId, Long institutionId, ListSignRequest request) {
        // Query children by institution 、 year & tags
        SearchRosterRequest searchChildRequest = new SearchRosterRequest();
        // searchChildRequest.setParentId(userId);
        // searchChildRequest.setTeacherId(teacherId);
        searchChildRequest.setCmId(institutionId.toString());
        searchChildRequest.setYear(request.getYear());
        searchChildRequest.setTgZt(TgStateEnum.TG_ZT.getValue());
        if (request.getTagId() != null) {
            searchChildRequest.setTagId(String.valueOf(request.getTagId()));
        }
        List<RosterResponse> children = rosterService.lisForPage(searchChildRequest);
        if (CollectionUtils.isEmpty(children)) {
            return Collections.emptyList();
        }

        List<Long> childIds = new ArrayList<>();
        for (RosterResponse childResponse : children) {
            childIds.add(childResponse.getId());
        }

        // Get signed childIds
        List<Long> signChilds = taskDetailMapper.listChildIdsByState(RollCallState.SIGNED, taskId, null);
        List<Long> unSignChildIds = ListUtils.removeAll(childIds, signChilds);

        // Build roster map by rosterId
        Map<String, RosterResponse> rosterMap = CommonUtil.listToObject(children, "id");

        return RollCallDataConvert.convertToUnsignList(unSignChildIds, rosterMap);
    }

    // TODO: 未点人员只显示托管状态为在托的人员，但点名记录需显示离校人员
    public ListSignResponse listSign(ListSignRequest request, Long institutionId) {

        // TODO: find task from cache
        Task task = taskMapper.selectByPrimaryKey(request.getTaskId());
        if (task == null) {
            throw new BusinessException("task.not.exist");
        }

        CallVo call = RollCallDataConvert.convertTaskToCallVo(task);

        // Query children by institution 、 year & tags
        SearchRosterRequest searchChildRequest = new SearchRosterRequest();
        // searchChildRequest.setParentId(userId);
        // searchChildRequest.setTeacherId(teacherId);
        searchChildRequest.setCmId(institutionId.toString());
        searchChildRequest.setYear(request.getYear());
        searchChildRequest.setTgZt(TgStateEnum.TG_ZT.getValue());
        if (request.getTagId() != null) {
            searchChildRequest.setTagId(String.valueOf(request.getTagId()));
        }
        List<RosterResponse> children = rosterService.lisForPage(searchChildRequest);
        if (CollectionUtils.isEmpty(children)) {
            return new ListSignResponse(call);
        }

        List<Long> childIds = new ArrayList<>();
        for (RosterResponse childResponse : children) {
            childIds.add(childResponse.getId());
        }

        // Build roster map by rosterId
        Map<String, RosterResponse> rosterMap = CommonUtil.listToObject(children, "id");

        List<TaskDetail> signList = taskDetailMapper.selectByChildIds(childIds, request.getTaskId(), null);

        // Build taskDetail map by rosterId(userId in taskdetail is rosterId)
        Map<String, TaskDetail> signRecordMap = CommonUtil.listToObject(signList, "userId");

        List<Long> signChilds = RollCallDataConvert.getUnsignChildId(signList);
        List<Long> unsignChildIds = ListUtils.removeAll(childIds, signChilds);

        // 未签到列表
        Map mapUnsign = RollCallDataConvert.convertToSignList(unsignChildIds, rosterMap, signRecordMap);
        List<ListSignItem> unsign = (List<ListSignItem>) (mapUnsign == null ? Collections.emptyList()
            : mapUnsign.get("unsign"));
        if (CollectionUtils.isEmpty(unsign)) {
            unsign = Collections.emptyList();
        }

        // 签到列表
        Map mapSign = RollCallDataConvert.convertToSignList(signChilds, rosterMap, signRecordMap);
        List<ListSignItem> sign = (List<ListSignItem>) (mapSign == null ? Collections.emptyList()
            : mapSign.get("signed"));
        if (CollectionUtils.isEmpty(sign)) {
            sign = Collections.emptyList();
        }

        ListSignResponse response = new ListSignResponse();
        response.setCall(call);
        response.setSign(sign);
        response.setUnsign(unsign);
        response.setSignNum(CollectionUtils.isEmpty(signList) ? 0 : sign.size());
        response.setLateNum(CommonUtil.toInteger(mapSign == null ? 0 : mapSign.get("wdrs"), 0));
        return response;
    }

    /**
     * 小孩签到
     *
     * @param request
     */
    public void sign(AddSignRequest request, User user) {

        Long childId = request.getChildId();
        Long taskId = request.getTaskId();

        Date signTime = new Date();
        //TODO(Kent): 性能优化
        synchronized (this) {
            TaskDetail taskDetail = taskDetailMapper.selectByChildIdAndTaskId(childId, request.getTaskId());

            if (taskDetail != null) {
                // 产品经理说不用给提示，所以有签到直接返回
                return;
            }

            TaskDetail signRecord = new TaskDetail();
            signRecord.setCreateBy(request.getTeacherId());
            signRecord.setCreateDate(signTime);
            signRecord.setDelFlag("1");
            signRecord.setState(RollCallState.INTIME.getValue());
            signRecord.setTaskId(request.getTaskId());
            signRecord.setUserId(childId);
            signRecord.setUpdateBy(request.getTeacherId());
            signRecord.setUpdateDate(signTime);
            taskDetailMapper.insertSelective(signRecord);
        }

        List<ParentChildResponse> parents = childService.getParentByChildId(String.valueOf(childId));
        if (CollectionUtils.isEmpty(parents)) {
            return;
        }

        Task task = this.getTaskById(taskId);
        Roster roster = rosterService.getRosterById(childId);
        String childName = roster == null ? "" : roster.getName();
        String taskName = task == null ? "" : task.getTaskName();
        InstitutionResponse institution = institutuionService.getById(user.getInstitutionId());
        String institutionName = institution == null ? "" : institution.getInstitutionName();

        //TODO(Kent): 加入队列推送消息

        StringBuffer sbf = new StringBuffer();
        sbf.append("您的孩子");
        sbf.append(childName);
        sbf.append("于");
        sbf.append(DateUtils.formatDate(signTime, DateEnum.HHMMSS_BYSEP));
        sbf.append("完成");
        sbf.append(taskName);
        sbf.append("，祝您生活愉快！\n");
        sbf.append(DateUtils.formatDate(signTime, DateEnum.YYYYMMDD_BYSEP));
        sbf.append(" ");
        sbf.append(institutionName);

        String content = sbf.toString();
        Chat chatHandler = ChatInstance.getChat(AppType.APESTAR.getValue());
        for (ParentChildResponse parent : parents) {
            if (parent == null || parent.getRingId() == null) {
                continue;
            }
            chatHandler.transmissionMessageFromOneToOne(PeoPleType.SYSTEM.getValue(), parent.getRingId(), content,
                TXT.getValue(), MessageWTType.PT.getValue());
        }

    }

    /**
     * 删除签到记录中的记录
     *
     * @param callId
     * @param childId
     * @param currentUserId
     */
    public void delSignRecord(Long callId, Long childId, Long currentUserId) {
        if (callId == null || childId == null) {
            // TODO: throw BusinessException
            return;
        }

        taskDetailMapper.delSignRecord(callId, childId, currentUserId);
    }

    // TODO: sort
    public ListSignDetailResponse listSignDetail(ListSignRequest request, Long institutionId) {
        // Get task by id TODO: find task from cache
        Task task = taskMapper.selectByPrimaryKey(request.getTaskId());
        if (task == null) {
            throw new BusinessException("task.not.exist");
        }
        CallVo call = RollCallDataConvert.convertTaskToCallVo(task);

        // Query children by institution
        SearchRosterRequest searchChildRequest = new SearchRosterRequest(institutionId.toString());
        List<RosterResponse> children = rosterService.lisForPage(searchChildRequest);
        if (CollectionUtils.isEmpty(children)) {
            return new ListSignDetailResponse(call);
        }

        List<Long> childIds = new ArrayList<>();
        for (RosterResponse childResponse : children) {
            childIds.add(childResponse.getId());
        }

        // Build roster map by rosterId
        Map<String, RosterResponse> rosterMap = CommonUtil.listToObject(children, "id");

        // Get signed list
        List<TaskDetail> signList = taskDetailMapper.selectByChildIds(childIds, request.getTaskId(), null);

        // Get teachers ids
        Set<Long> teacherIds = RollCallDataConvert.getTeacherId(signList);
        // Get info of teachers
        Map<Long, User> userInfoMap = userService.multiGetUserByIds(teacherIds);

        // Vo convert
        List<SignDetailItem> signDetailItems = RollCallDataConvert
            .convertToSignDetailList(signList, rosterMap, userInfoMap);

        // return
        ListSignDetailResponse response = new ListSignDetailResponse();
        response.setCall(call);
        response.setSignNum(CollectionUtils.isEmpty(signList) ? 0 : signList.size());
        response.setSign(signDetailItems);
        return response;
    }
}
